package com.beemans.topon.ads

import android.widget.FrameLayout
import androidx.annotation.Keep
import androidx.core.view.contains
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.anythink.banner.api.ATBannerListener
import com.anythink.banner.api.ATBannerView
import com.anythink.core.api.ATAdConst
import com.anythink.core.api.ATAdInfo
import com.anythink.core.api.AdError
import com.beemans.topon.kts.context
import com.beemans.topon.kts.lifecycleOwnerEx
import com.beemans.topon.log.Logger
import java.util.concurrent.ConcurrentHashMap

/**
 * @author ti
 * @date 2022/10/19.
 */
object TpBannerAd {
    private val logTag by lazy { this::class.java.simpleName }
    private val adLoaderMap by lazy { ConcurrentHashMap<String, MutableList<TpBannerAdLoader>>() }

    /**
     * 开始加载广告
     *
     * @param owner 传入 Activity 或 Fragment
     * @param config 广告配置
     * @param flContainer 广告视图容器
     * @param bannerAdCallback 广告回调
     */
    fun start(
        owner: LifecycleOwner,
        config: TpBannerAdConfig,
        flContainer: FrameLayout?,
        bannerAdCallback: (TpBannerAdCallback.() -> Unit)? = null
    ) {
        val loader = TpBannerAdLoader(owner, config, flContainer, bannerAdCallback)
        start(loader)
    }

    /**
     * 开始加载广告
     *
     * @param loader 广告加载器
     */
    fun start(loader: TpBannerAdLoader) {
        val placementId = loader.config.placementId
        val loaders = adLoaderMap.getOrPut(placementId) { mutableListOf() }
        if (!loaders.contains(loader)) {
            loaders.add(loader)
            adLoaderMap[placementId] = loaders
        }
        //当前有其他相同广告位正在加载广告时，等待加载
        if (loaders.any { it.isAdRequesting() }) {
            return
        }
        loader.start()
    }

    /**
     * 开始加载列表中最近的一个
     */
    private fun startNext(oldLoader: TpBannerAdLoader) {
        val placementId = oldLoader.config.placementId
        val loaders = adLoaderMap[placementId]
        loaders?.lastOrNull()?.let { start(it) }
    }

    /**
     * 从列表中移除对应的加载
     */
    private fun removeLoader(
        loader: TpBannerAdLoader,
        callback: (list: List<TpBannerAdLoader>) -> Unit = {}
    ) {
        val placementId = loader.config.placementId
        val loaders = adLoaderMap[placementId]
        if (loaders.isNullOrEmpty()) return
        loaders.remove(loader)
        adLoaderMap[placementId] = loaders
        callback.invoke(loaders)
    }

    /**
     * 广告加载器
     *
     * @param owner 传入 Activity 或 Fragment
     * @param config 广告配置
     * @param flContainer 广告视图容器
     * @param bannerAdCallback 广告回调
     */
    class TpBannerAdLoader(
        private val owner: LifecycleOwner,
        val config: TpBannerAdConfig,
        private val flContainer: FrameLayout?,
        private val bannerAdCallback: (TpBannerAdCallback.() -> Unit)? = null
    ) : DefaultLifecycleObserver, ATBannerListener {
        private val context by lazy { owner.context }
        private val placementId by lazy { config.placementId }
        private val adViewWidth by lazy { config.adViewWidth }
        private val adViewHeight by lazy { config.adViewHeight }

        private var callback = bannerAdCallback?.let { TpBannerAdCallback().apply(it) }
        private var bannerAdLayout: FrameLayout? = flContainer
        private var tpAdStatus: TpBannerAdStatus? = null
        private var atBannerView: ATBannerView? = null

        init {
            init()
        }

        private fun init() {
            owner.lifecycleOwnerEx.lifecycle.addObserver(this)
        }

        override fun onBannerLoaded() {
            onAdLoaded()
        }

        override fun onBannerFailed(adError: AdError?) {
            onAdLoadFailed(adError)
        }

        override fun onBannerClicked(atAdInfo: ATAdInfo?) {
            Logger.logI(logTag, "onAdClick --- atAdInfo:$atAdInfo")
            callback?.onAdClick?.invoke(atAdInfo)
        }

        override fun onBannerShow(atAdInfo: ATAdInfo?) {
            Logger.logI(logTag, "onAdShow --- atAdInfo:$atAdInfo")
            tpAdStatus?.isShowing = true
            callback?.onAdShow?.invoke(atAdInfo)
        }

        override fun onBannerClose(atAdInfo: ATAdInfo?) {
            val isCloseAd = callback?.onAdClose?.invoke(atAdInfo) ?: true
            if (isCloseAd) {
                Logger.logI(logTag, "onAdClose --- atAdInfo:$atAdInfo")
                onAdRelease()
            }
        }

        override fun onBannerAutoRefreshed(atAdInfo: ATAdInfo?) {
            Logger.logI(logTag, "onBannerAutoRefreshed --- atAdInfo:$atAdInfo")
            onAdLoaded()
        }

        override fun onBannerAutoRefreshFail(adError: AdError?) {
        }

        /**
         * 是否正在请求广告
         */
        fun isAdRequesting(): Boolean {
            return tpAdStatus?.isRequesting == true
        }

        /**
         * 获取广告加载器
         */
        private fun getAtBannerView(): ATBannerView {
            return ATBannerView(context).apply {
                val viewHeight = when {
                    config.isAdaptiveHeight -> FrameLayout.LayoutParams.WRAP_CONTENT
                    else -> adViewHeight
                }
                layoutParams = FrameLayout.LayoutParams(adViewWidth, viewHeight)
                setPlacementId(placementId)

                setLocalExtra(mutableMapOf<String, Any>().apply {
                    put(ATAdConst.KEY.AD_WIDTH, adViewWidth)
                    put(ATAdConst.KEY.AD_HEIGHT, adViewHeight)
                })

                setBannerAdListener(this@TpBannerAdLoader)
            }
        }

        /**
         * 开始加载广告
         */
        internal fun start() {
            if (atBannerView == null) {
                atBannerView = getAtBannerView()
            }
            if (bannerAdLayout == null) {
                bannerAdLayout = flContainer
            }
            if (callback == null) {
                callback = bannerAdCallback?.let { TpBannerAdCallback().apply(it) }
            }
            if (atBannerView != null
                && bannerAdLayout?.contains(atBannerView!!) != true
            ) {
                bannerAdLayout?.removeAllViews()
                bannerAdLayout?.addView(atBannerView)
            }
            tpAdStatus = TpBannerAdStatus(placementId).apply {
                isStarted = true
                isRequesting = true
            }

            Logger.logI(logTag, "onAdStart")
            callback?.onAdStart?.invoke()

            atBannerView?.loadAd()
        }

        /**
         * 广告加载成功
         */
        private fun onAdLoaded() {
            onAdLoadComplete {
                Logger.logI(logTag, "onAdLoaded")
                callback?.onAdLoaded?.invoke()
                startNext(this)
            }
        }

        /**
         * 广告加载失败
         */
        private fun onAdLoadFailed(adError: AdError?) {
            onAdLoadComplete {
                Logger.logI(logTag, "onAdLoadFailed --- adError:$adError")
                callback?.onAdLoadFailed?.invoke(adError)
                startNext(this)
            }
        }

        /**
         * 广告加载完成
         */
        private fun onAdLoadComplete(callback: () -> Unit) {
            tpAdStatus?.isRequesting = false

            if (tpAdStatus?.isLoadCompleted == false) {
                tpAdStatus?.isLoadCompleted = true
                removeLoader(this)
                callback.invoke()
            }
        }

        /**
         * 获取缓存信息
         */
        fun checkValidAdCaches(): List<ATAdInfo> {
            val atBannerView = this.atBannerView ?: getAtBannerView()
            return atBannerView.checkValidAdCaches() ?: listOf()
        }

        /**
         * 广告释放
         */
        fun onAdRelease() {
            bannerAdLayout?.removeAllViews()
            bannerAdLayout = null
            atBannerView?.destroy()
            atBannerView = null
            tpAdStatus = null
            callback = null
        }

        override fun onDestroy(owner: LifecycleOwner) {
            owner.lifecycle.removeObserver(this)
            onAdRelease()
            removeLoader(this)
        }
    }

    @Keep
    data class TpBannerAdStatus(
        val placementId: String,                //广告位id
        var isStarted: Boolean = false,         //广告是否已开始加载
        var isRequesting: Boolean = false,      //广告正在加载中
        var isShowing: Boolean = false,         //广告正在展示中
        var isLoadCompleted: Boolean = false,   //广告已加载完成（加载成功 or 加载失败）
    )

    @Keep
    data class TpBannerAdConfig(
        var placementId: String,                //广告位id
        var adViewWidth: Int,                   //广告视图宽度，大于0生效
        var adViewHeight: Int,                  //广告视图高度，大于0生效
        var isAdaptiveHeight: Boolean = true,   //是否自适应高度
    )

    class TpBannerAdCallback {
        var onAdStart: (() -> Unit)? = null
        var onAdLoaded: (() -> Unit)? = null
        var onAdLoadFailed: ((adError: AdError?) -> Unit)? = null
        var onAdShow: ((atAdInfo: ATAdInfo?) -> Unit)? = null
        var onAdClick: ((atAdInfo: ATAdInfo?) -> Unit)? = null
        var onAdClose: ((atAdInfo: ATAdInfo?) -> Boolean)? = null

        fun onAdStart(onAdStart: () -> Unit) {
            this.onAdStart = onAdStart
        }

        fun onAdLoaded(onAdLoaded: () -> Unit) {
            this.onAdLoaded = onAdLoaded
        }

        fun onAdLoadFailed(onAdLoadFailed: (adError: AdError?) -> Unit) {
            this.onAdLoadFailed = onAdLoadFailed
        }

        fun onAdShow(onAdShow: (atAdInfo: ATAdInfo?) -> Unit) {
            this.onAdShow = onAdShow
        }

        fun onAdClick(onAdClick: (atAdInfo: ATAdInfo?) -> Unit) {
            this.onAdClick = onAdClick
        }

        fun onAdClose(onAdClose: (atAdInfo: ATAdInfo?) -> Boolean) {
            this.onAdClose = onAdClose
        }
    }
}